#include <assert.h>
#include <ctype.h>
#include <locale.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


#define MAX_ARRAY_LENGTH 20 //  定义常量来增强可读性

#undef  FILE_SIZE // 取消已定义的 FILE_SIZE
#define FILE_SIZE 42 // 并定义它为 42


#ifndef MESSAGE // 告诉 CPP 只有当 MESSAGE 未定义时，才定义 MESSAGE
   #define MESSAGE "You wish!"
#endif

void predefine_macro(void)
{
    printf("***** predefine_macro *****\n");
    printf("File :%s\n", __FILE__ );
    printf("Date :%s\n", __DATE__ );
    printf("Time :%s\n", __TIME__ );
    printf("Line :%d\n", __LINE__ );
    printf("ANSI :%d\n", __STDC__ );
}

void macro_continuation_operator(void)
{
    printf("***** macro_continuation_operator *****\n");
    #define message_for(a, b) \
        printf(#a " and " #b ": We love you!\n")
        // 在宏定义中，当需要把一个宏的参数转换为字符串常量时，则使用字符串常量化运算符（#）
    message_for("d", "s");
}

// 字符串常量化运算符（#）和标记粘贴运算符（##）
void tag_paste_operator(void)
{
    printf("***** tag_paste_operator *****\n");
    #define tokenpaster(n) printf("token" #n " = %d\n", token##n)
    
    int token34 = 40;

    tokenpaster(34);
}

void preprocessor_defined_operator(void)
{
    printf("***** preprocessor_defined_operator *****\n");
    
    #if !defined ( MESSAGE )
        #define MESSAGE "You wish!"
    #endif

    printf("Here is the message : %s\n", MESSAGE);
}

void parameterized_macro(void)
{
    printf("***** parameterized_macro *****\n");
    #define square(x) (x * x)
    #define MAX(x,y) (x>y? x:y)

    printf("square(3): %d\n", square(3));
    printf("MAX(3,4): %d\n", MAX(3,4));
}

void main(void)
{
    predefine_macro();
    macro_continuation_operator();
    tag_paste_operator();
    preprocessor_defined_operator();
    parameterized_macro();
    system("pause");
}

/*
C 预处理器不是编译器的组成部分，但是它是编译过程中一个单独的步骤
C 预处理器只不过是一个文本替换工具
指示编译器在实际编译之前完成所需的预处理

所有重要的预处理器指令
    指令	描述
    #define	定义宏
    #include	包含一个源代码文件
    #undef	取消已定义的宏
    #ifdef	如果宏已经定义，则返回真
    #ifndef	如果宏没有定义，则返回真
    #if	如果给定条件为真，则编译下面代码
    #else	#if 的替代方案
    #elif	如果前面的 #if 给定条件不为真，当前条件为真，则编译下面代码
    #endif	结束一个 #if……#else 条件编译块
    #error	当遇到标准错误时，输出错误消息
    #pragma	使用标准化方法，向编译器发布特殊的命令到编译器中

预定义宏
    宏	描述
    __DATE__	当前日期，一个以 "MMM DD YYYY" 格式表示的字符常量。
    __TIME__	当前时间，一个以 "HH:MM:SS" 格式表示的字符常量。
    __FILE__	这会包含当前文件名，一个字符串常量。
    __LINE__	这会包含当前行号，一个十进制常量。
    __STDC__	当编译器以 ANSI 标准编译时，则定义为 1。
*/